Rhapsody Developer Release Copyright © 1998
by Apple Computer, Inc. All Rights Reserved.
This release note provides some guidelines for writing a threaded application in the current release (Developer Release 2) of Rhapsody. For a related discussion, see Thread-safe Classes in Foundation in the release notes for the Foundation framework.
[NSApplication detachDrawingThread:]
to create a
thread with its own graphics context).lockFocus
and
unlockFocus
(just as in the single-threaded
case).[NSApplication
run]
calling [NSApplication nextEventMatchingMask:
...]
and [NSApplication sendEvent:]
. While the
Application Kit continues to work if other threads are involved in
the event path, operations can occur out of sequence. For example
if two different threads are responding to key events, the keys
could be received out of order. By letting the main thread process
events, you achieve a more consistent user experience. The main
thread can send a message (DO, Mach message, or through a
NSConditionLock) to get another thread to do some work.Note: The Java Yellow Box API implementation (including AWT) is multi-threaded.
The major reward from multi-threading your application is improved performance on a multi-processor system.
Only one thread can use an NSDPSContext at a time. A thread can use multiple NSDPSContexts during its lifetime, but if two threads access a single NSDPSContext at the same time, unpredictable results can occur.
Flushing still occurs automatically after every event in the main
thread of the application. However, there are times when you need to
explicitly flush when drawing on other threads. Use the
flush:
and flushGraphics:
methods of
NSDPSContext to flush the stream buffer and window backing store,
respectively.
One thread can create an image, draw it, pass it off to another thread, which can then draw it, and so forth. The underlying image cache is shared among all threads.
You can create, destroy, resize, move, and perform other
operations with NSViews from different threads. The system ensures
that all drawing is deferred while these operations occur (through
the lockFocus
and unlockFocus
mentioned
above).
In a multi-threaded application, the main thread is still
responsible for redisplaying dirty views through the same process as
a single-threaded application. The drawRect:
method of
every dirty view is called in the main thread. If the drawing needs
to be done on another thread, the drawRect:
method for
the view should arrange for secondary thread to do the drawing and
not do any drawing in drawRect:
.
If a secondary thread of an application wants to cause portions of
the view to be redrawn on the main thread, the normal mechanisms work
(setNeedsDisplay:
, setNeedsDisplayInRect:
,
and setViewsNeedDisplay:
).
Performance Note: The view system's gstates are per-thread. Using
gstates in a multi-threaded application improves drawing performance
in a way similar to a single-threaded application. Please use the
public method (gstate
) to get at the gstate of the
current thread.
The collection classes in Foundation (for example, NSMutableArray, NSMutableDictionary) are not thread-safe. You must lock around them to use them in a multi-threaded application:
Not Thread-Safe:
thread-1 thread-2
count = [array count]; for (i = 0; i < count; i++) { [array addObject:newObject]; if ([array objectAtIndex:i] == obj) { // ... do something ... } }
In this example, if thread-1 were preempted while it iterated over the array, the second thread, thread-2 , could be scheduled and add an object to the array. When the first thread, thread-1, ran again, it's count variable would be stale, and it may not find the desired object.
Thread-Safe :
thread-1 thread-2
[arrayLock lock]; count = [array count]; for (i = 0; i < count; i++) { [arrayLock lock]; if ([array objectAtIndex:i] == obj) { [array addObject:newObject]; // ... do something ... [arrayLock unlock]; } } [arrayLock unlock];
This is the same example using locks around the array manipulation. The first thread will complete its entire iteration before the second thread can access the array.
Note: See Foundation release notes for more information on Foundation thread support.
The Window System (NSWindow, NSPanel) is not thread-safe. The
workaround in this release is to let the windows be created by the
main thread (threads could be created in a view's init
or awakeFromNib:
methods).
Thread termination can cause some drawing problems. In general, the Application Kit doesn't know if your application is using threads to draw or do similar operations. Before dimissing a window, you should ensure that your threads have stopped drawing.
Using locks within drawRect:
can cause deadlock
problems if they are held beyond the drawRect:
. It is
safe to lock and unlock NSLocks within a drawRect:
.